package com.cs.framework.web.handler.support;

import java.io.IOException;
import java.io.InputStream;

import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.support.ServletContextResourcePatternResolver;

import com.cs.framework.common.util.CommonUtils;
import com.cs.framework.common.util.IOUtils;
import com.cs.framework.core.context.Application;
import com.cs.framework.core.util.CoreConstant;
import com.cs.framework.web.context.WebApplication;
import com.cs.framework.web.exception.WebExceptionHelper;
import com.cs.framework.web.handler.Handler;
import com.cs.framework.web.util.RequestUtils;
import com.cs.framework.web.util.WebConstant;
import com.cs.framework.web.view.ViewInfo;

/**
 * 资源处理器
 * 
 * @author hedongzhou
 *
 */
public class ResourceHandler implements Handler {

	private final Log logger = LogFactory.getLog(getClass());

	/**
	 * 资源路径
	 */
	private String[] resources;

	/**
	 * 资源解析器
	 */
	private ServletContextResourcePatternResolver resolver;

	/**
	 * 初始化
	 * 
	 * @param application
	 *            应用上下文
	 */
	public void init(Application application) {
		String resourcePath = (String) application.getProperty(WebConstant.RESOURCES_PROPERTY);

		if (CommonUtils.isNotEmpty(resourcePath)) {
			resources = resourcePath.split(CoreConstant.CONF_SEPARATE);
			resolver = new ServletContextResourcePatternResolver(((WebApplication) application).getServletContext());
		}
	}

	/**
	 * 判断是否可以处理请求
	 * 
	 * @param request
	 * @return
	 */
	public boolean canHandler(HttpServletRequest request) {
		if (CommonUtils.isNotEmpty(resources)) {
			return IOUtils.match(resources, RequestUtils.getResource(request));
		}

		return false;
	}

	/**
	 * 处理请求
	 * 
	 * @param request
	 * @param response
	 * @return
	 */
	public ViewInfo handler(HttpServletRequest request, HttpServletResponse response) {
		String resourcePath = RequestUtils.getResource(request);

		Resource resource = resolver.getResource(resourcePath);

		if (resource == null || !resource.exists()) {
			WebExceptionHelper.throwWebException("W009", resourcePath);
		}

		MediaType mediaType = getMediaType(request, resource);

		try {
			setHeaders(response, resource, mediaType);
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
			WebExceptionHelper.throwWebException(e, "W012");
		}

		try {
			StreamUtils.copy(resource.getInputStream(), response.getOutputStream());
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
			WebExceptionHelper.throwWebException(e, "W013");
		}

		return null;
	}

	protected MediaType getMediaType(HttpServletRequest request, Resource resource) {
		MediaType mediaType = null;

		String mimeType = request.getSession().getServletContext().getMimeType(resource.getFilename());

		if (CommonUtils.isNotEmpty(mimeType)) {
			mediaType = MediaType.parseMediaType(mimeType);
		}

		if (mediaType == null || MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) {
			MediaType jafMediaType = ActivationMediaTypeFactory.getMediaType(resource.getFilename());
			if (jafMediaType != null && !MediaType.APPLICATION_OCTET_STREAM.equals(jafMediaType)) {
				mediaType = jafMediaType;
			}
		}

		return mediaType;
	}

	protected void setHeaders(HttpServletResponse response, Resource resource, MediaType mediaType) throws IOException {
		response.setContentLength((int) resource.contentLength());

		if (mediaType != null) {
			response.setContentType(mediaType.toString());
		}
	}

	protected static class ActivationMediaTypeFactory {

		private static final FileTypeMap fileTypeMap;

		static {
			fileTypeMap = loadFileTypeMapFromContextSupportModule();
		}

		private static FileTypeMap loadFileTypeMapFromContextSupportModule() {
			Resource mappingLocation = new ClassPathResource("org/springframework/mail/javamail/mime.types");
			if (mappingLocation.exists()) {
				InputStream inputStream = null;
				try {
					inputStream = mappingLocation.getInputStream();
					return new MimetypesFileTypeMap(inputStream);
				} catch (IOException ex) {
				} finally {
					if (inputStream != null) {
						try {
							inputStream.close();
						} catch (IOException ex) {
						}
					}
				}
			}
			return FileTypeMap.getDefaultFileTypeMap();
		}

		public static MediaType getMediaType(String filename) {
			String mediaType = fileTypeMap.getContentType(filename);
			return (StringUtils.hasText(mediaType) ? MediaType.parseMediaType(mediaType) : null);
		}

	}

}
